#ifndef _PN_H
#define _PN_H

#include <vector>
#include <cassert>
#include <cmath>
#include <map>
#include <string>

using namespace std;

 class posNeg { // a positive or negative example
      double sk; // self-kernel value
   
   public: 
      vector <int> str, pt;  
      vector <int> bw,aw,bp,ap; // before words, after words, before pos, after pos 
      vector <int> strW, ptW; // with the words in the window
      
      vector <int> nt, ntst, nten; // non-terminals, their start and end
      vector <int> ntw, ntp; // string with words and entities, string with pos and entities
      vector <int> ntwW, ntpW; // with windows, string with words and entities, string with pos and entities

      vector <vector <string> > path;
      vector <vector <double> > pathProb;


      bool extraFeatures; 
      bool cap, allCap;
      bool di, allDi;
      bool ga, allGa;
      bool ment,ing;
      
      string g; // gfeature
      
      map <int, double> k; // kernel values with other examples

      posNeg(const vector <int> &pstr, const vector <int> &ppt,  const vector <int> &pbw, const vector <int> &paw,  const vector <int> &pbp, const vector <int> &pap,const vector <int> &pntw, const vector <int> &pntp, bool ef);

      void addPath(const vector <vector <string> > &p, const vector <vector <double> > &pp) {
	 path = p;
	 pathProb = pp;
      }

      //posNeg(const vector <int> &s, const vector <int> &p,  const vector <int> &bw, const vector <int> &aw,  const vector <int> &bp, const vector <int> &ap, bool ef=false);
      //posNeg(const vector <int> &s, const vector <int> &p,  const vector <int> &bw, const vector <int> &aw,  const vector <int> &bp, const vector <int> &ap, const vector <int> &pnt, const vector <int> &pntst, const vector <int> &pnten, bool ef=false);

      double selfK() const {
	 assert (sk != -1);
	 return sk;
      }
      void putSelfK(double psk) {
	 sk = psk;
      }

      bool operator==(const posNeg &other) const {
	 if (extraFeatures != other.extraFeatures) return false;
	 if (str != other.str) return false;
	 if (pt != other.pt) return false;
	 if (bw != other.bw) return false;
	 if (aw != other.aw) return false;
	 if (bp != other.bp) return false;
	 if (ap != other.ap) return false;
	 if (ntp != other.ntp) return false;
	 if (ntw != other.ntw) return false;
	 return true;
      }
      bool operator != (const posNeg &other) const {
	 return !operator==(other);
      }

      void writeStr(ostream &out) const;
 };

class pn { // collection of pos & neg examples
   vector <posNeg> pone;
   vector <vector <int> >  ponePresent;

   double relationKernel(const posNeg &p1, const posNeg &p2) const;

   double ncsUn(const vector <int> &x, const vector <int> &y) const;
   // unnormalized string-subsequence kernel value
   
   public:

   pn () {
      ponePresent.resize(1000000);
   }

   vector <int> giveStr(int i) const {
      assert(i < pone.size());
      return pone[i].str;
   }
   double giveSelfK(int i) const {
      assert(i < pone.size());
      return pone[i].selfK();
   }

   void writeStr(ostream &out, int i) const;
   
   int add(posNeg &eg);

   double kernelUn(int i, int j);
   double kernelUn(pn &tsw, int i, int j);
   double kernel(int i, int j) {
     return kernelUn(i,j)/sqrt(pone[i].selfK()*pone[j].selfK());
   }
   double kernel(pn &tsw, int i, int j) {
     return kernelUn(tsw,i,j)/sqrt(tsw.pone[i].selfK()*pone[j].selfK());
   }
};

#endif
